package utils

import (
	"fmt"
	"math/rand"
	"testing"
	"time"

	"gorm.io/driver/postgres"
	"gorm.io/gorm"
	"gorm.io/gorm/logger"
)

// TestDB 测试数据库配置
type TestDB struct {
	DB      *gorm.DB
	Config  *DBConfig
	cleanup func()
	dbName  string
}

// DBConfig 数据库配置
type DBConfig struct {
	Host     string
	Port     int
	Database string
	User     string
	Password string
	SSLMode  string
}

// SetupTestDatabase 创建测试数据库
func SetupTestDatabase(t *testing.T) *TestDB {
	// 生成随机数据库名
	rand.Seed(time.Now().UnixNano())
	dbName := fmt.Sprintf("rdiot_test_%d_%d", time.Now().Unix(), rand.Intn(10000))

	config := &DBConfig{
		Host:     "localhost",
		Port:     5432,
		Database: dbName,
		User:     "postgres",
		Password: "Abc@123456",
		SSLMode:  "disable",
	}

	// 连接到postgres默认数据库创建测试数据库
	masterDSN := fmt.Sprintf("host=%s port=%d user=%s password=%s dbname=postgres sslmode=%s",
		config.Host, config.Port, config.User, config.Password, config.SSLMode)

	masterDB, err := gorm.Open(postgres.Open(masterDSN), &gorm.Config{
		Logger: logger.Default.LogMode(logger.Silent),
	})
	if err != nil {
		t.Fatalf("连接主数据库失败: %v", err)
	}

	// 创建测试数据库
	sqlDB, _ := masterDB.DB()
	_, err = sqlDB.Exec(fmt.Sprintf("CREATE DATABASE %s", dbName))
	if err != nil {
		t.Fatalf("创建测试数据库失败: %v", err)
	}
	sqlDB.Close()

	// 连接到测试数据库
	testDSN := fmt.Sprintf("host=%s port=%d user=%s password=%s dbname=%s sslmode=%s",
		config.Host, config.Port, config.User, config.Password, config.Database, config.SSLMode)

	testDB, err := gorm.Open(postgres.Open(testDSN), &gorm.Config{
		Logger: logger.Default.LogMode(logger.Silent),
	})
	if err != nil {
		t.Fatalf("连接测试数据库失败: %v", err)
	}

	// 运行迁移
	err = runTestMigrations(testDB)
	if err != nil {
		t.Fatalf("运行测试迁移失败: %v", err)
	}

	return &TestDB{
		DB:     testDB,
		Config: config,
		dbName: dbName,
		cleanup: func() {
			// 关闭连接
			sqlDB, _ := testDB.DB()
			sqlDB.Close()

			// 重新连接主数据库删除测试数据库
			masterDB, err := gorm.Open(postgres.Open(masterDSN), &gorm.Config{
				Logger: logger.Default.LogMode(logger.Silent),
			})
			if err == nil {
				sqlDB, _ := masterDB.DB()
				sqlDB.Exec(fmt.Sprintf("DROP DATABASE IF EXISTS %s", dbName))
				sqlDB.Close()
			}
		},
	}
}

// Cleanup 清理测试数据库
func (tdb *TestDB) Cleanup() {
	if tdb.cleanup != nil {
		tdb.cleanup()
	}
}

// runTestMigrations 运行测试迁移
func runTestMigrations(db *gorm.DB) error {
	// 这里应该运行我们的迁移脚本
	// 为了简化，我们直接创建基本表结构
	sqlStatements := []string{
		// entity_templates 表
		`CREATE TABLE IF NOT EXISTS entity_templates (
			id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
			name VARCHAR(100) NOT NULL UNIQUE,
			display_name VARCHAR(200) NOT NULL,
			description TEXT,
			category VARCHAR(50) NOT NULL,
			icon VARCHAR(100),
			is_active BOOLEAN NOT NULL DEFAULT true,
			created_at TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT NOW(),
			updated_at TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT NOW()
		)`,

		// attribute_definitions 表
		`CREATE TABLE IF NOT EXISTS attribute_definitions (
			id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
			template_id UUID NOT NULL REFERENCES entity_templates(id) ON DELETE CASCADE,
			name VARCHAR(100) NOT NULL,
			display_name VARCHAR(200) NOT NULL,
			data_type VARCHAR(20) NOT NULL CHECK (data_type IN ('string', 'number', 'boolean', 'datetime', 'reference', 'array', 'json')),
			is_required BOOLEAN NOT NULL DEFAULT false,
			default_value TEXT,
			validation_rules JSONB,
			sort_order INTEGER NOT NULL DEFAULT 0,
			created_at TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT NOW(),
			updated_at TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT NOW(),
			UNIQUE(template_id, name)
		)`,

		// entity_instances 表
		`CREATE TABLE IF NOT EXISTS entity_instances (
			id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
			template_id UUID NOT NULL REFERENCES entity_templates(id) ON DELETE RESTRICT,
			name VARCHAR(200) NOT NULL,
			description TEXT,
			status VARCHAR(20) NOT NULL DEFAULT 'active' CHECK (status IN ('active', 'inactive', 'deleted')),
			tags TEXT[],
			created_at TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT NOW(),
			updated_at TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT NOW(),
			UNIQUE(template_id, name)
		)`,

		// attribute_values_string 表
		`CREATE TABLE IF NOT EXISTS attribute_values_string (
			id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
			entity_id UUID NOT NULL REFERENCES entity_instances(id) ON DELETE CASCADE,
			attribute_name VARCHAR(100) NOT NULL,
			value TEXT,
			created_at TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT NOW(),
			updated_at TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT NOW(),
			UNIQUE(entity_id, attribute_name)
		)`,

		// attribute_values_number 表
		`CREATE TABLE IF NOT EXISTS attribute_values_number (
			id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
			entity_id UUID NOT NULL REFERENCES entity_instances(id) ON DELETE CASCADE,
			attribute_name VARCHAR(100) NOT NULL,
			value DECIMAL(20,8),
			created_at TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT NOW(),
			updated_at TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT NOW(),
			UNIQUE(entity_id, attribute_name)
		)`,

		// attribute_values_boolean 表
		`CREATE TABLE IF NOT EXISTS attribute_values_boolean (
			id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
			entity_id UUID NOT NULL REFERENCES entity_instances(id) ON DELETE CASCADE,
			attribute_name VARCHAR(100) NOT NULL,
			value BOOLEAN,
			created_at TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT NOW(),
			updated_at TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT NOW(),
			UNIQUE(entity_id, attribute_name)
		)`,

		// attribute_values_datetime 表
		`CREATE TABLE IF NOT EXISTS attribute_values_datetime (
			id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
			entity_id UUID NOT NULL REFERENCES entity_instances(id) ON DELETE CASCADE,
			attribute_name VARCHAR(100) NOT NULL,
			value TIMESTAMP WITH TIME ZONE,
			created_at TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT NOW(),
			updated_at TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT NOW(),
			UNIQUE(entity_id, attribute_name)
		)`,

		// attribute_values_reference 表
		`CREATE TABLE IF NOT EXISTS attribute_values_reference (
			id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
			entity_id UUID NOT NULL REFERENCES entity_instances(id) ON DELETE CASCADE,
			attribute_name VARCHAR(100) NOT NULL,
			value UUID,
			created_at TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT NOW(),
			updated_at TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT NOW(),
			UNIQUE(entity_id, attribute_name)
		)`,

		// attribute_values_jsonb 表 (用于array和json类型)
		`CREATE TABLE IF NOT EXISTS attribute_values_jsonb (
			id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
			entity_id UUID NOT NULL REFERENCES entity_instances(id) ON DELETE CASCADE,
			attribute_name VARCHAR(100) NOT NULL,
			value JSONB,
			created_at TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT NOW(),
			updated_at TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT NOW(),
			UNIQUE(entity_id, attribute_name)
		)`,

		// 创建必要的索引
		`CREATE INDEX IF NOT EXISTS idx_entity_templates_category ON entity_templates(category)`,
		`CREATE INDEX IF NOT EXISTS idx_entity_templates_is_active ON entity_templates(is_active)`,
		`CREATE INDEX IF NOT EXISTS idx_attribute_definitions_template_id ON attribute_definitions(template_id)`,
		`CREATE INDEX IF NOT EXISTS idx_entity_instances_template_id ON entity_instances(template_id)`,
		`CREATE INDEX IF NOT EXISTS idx_entity_instances_status ON entity_instances(status)`,
		`CREATE INDEX IF NOT EXISTS idx_attr_string_entity_id ON attribute_values_string(entity_id)`,
		`CREATE INDEX IF NOT EXISTS idx_attr_number_entity_id ON attribute_values_number(entity_id)`,
		`CREATE INDEX IF NOT EXISTS idx_attr_boolean_entity_id ON attribute_values_boolean(entity_id)`,
		`CREATE INDEX IF NOT EXISTS idx_attr_datetime_entity_id ON attribute_values_datetime(entity_id)`,
		`CREATE INDEX IF NOT EXISTS idx_attr_reference_entity_id ON attribute_values_reference(entity_id)`,
		`CREATE INDEX IF NOT EXISTS idx_attr_jsonb_entity_id ON attribute_values_jsonb(entity_id)`,
	}

	for _, stmt := range sqlStatements {
		if err := db.Exec(stmt).Error; err != nil {
			return fmt.Errorf("执行迁移语句失败: %v", err)
		}
	}

	return nil
}

// TruncateAllTables 清空所有表数据（用于测试间清理）
func (tdb *TestDB) TruncateAllTables() error {
	tables := []string{
		"attribute_values_string",
		"attribute_values_number",
		"attribute_values_boolean",
		"attribute_values_datetime",
		"attribute_values_reference",
		"attribute_values_jsonb",
		"entity_instances",
		"attribute_definitions",
		"entity_templates",
	}

	for _, table := range tables {
		if err := tdb.DB.Exec(fmt.Sprintf("TRUNCATE TABLE %s CASCADE", table)).Error; err != nil {
			return fmt.Errorf("清空表 %s 失败: %v", table, err)
		}
	}

	return nil
}
